package com.tepth.remote.control.service;

import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.IBinder;
import android.os.PowerManager;
import android.support.annotation.Nullable;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.baidu.location.BDLocation;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.blankj.utilcode.constant.TimeConstants;
import com.blankj.utilcode.util.ThreadUtils;
import com.blankj.utilcode.util.TimeUtils;
import com.tencent.bugly.crashreport.BuglyLog;
import com.tepth.remote.control.R;
import com.tepth.remote.control.base.bean.Gps;
import com.tepth.remote.control.base.bean.NotificationBean;
import com.tepth.remote.control.base.config.ApiDictionary;
import com.tepth.remote.control.base.config.SpKey;
import com.tepth.remote.control.base.event.CalendarEvent;
import com.tepth.remote.control.base.event.LocationEvent;
import com.tepth.remote.control.base.event.RequestLocationEvent;
import com.tepth.remote.control.base.listener.ControlLocationListener;
import com.tepth.remote.control.manager.ConfigManager;
import com.tepth.remote.control.manager.ControlNotificationManager;
import com.tepth.remote.core.app.Control;
import com.tepth.remote.core.net.CommonParams;
import com.tepth.remote.core.net.callback.ISoapSuccess;
import com.tepth.remote.core.net.soap.SoapClient;
import com.tepth.remote.core.utils.location.LocationUtil;
import com.tepth.remote.core.utils.storage.ControlPreference;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.ksoap2.serialization.SoapObject;

import java.util.ArrayList;
import java.util.WeakHashMap;
import java.util.concurrent.TimeUnit;

/**
 * Description:
 *
 * @author Hequn.Lee
 * @date 2018/11/9
 */
public class ControlService extends Service {

    private final static int CONTROL_SERVICE_ID = 1001;
    private LocationClient mLocationClient = null;
    private ControlLocationListener mControlLocationListener = new ControlLocationListener();
    private final Object lock = new Object();
    private final ArrayList<JSONObject> gpsList = new ArrayList<>();
    private static final int OVER_TIME_SECOND = 560;
    private static final int MAX_GPS_LIST_SIZE = 15;
    private static final int WAKE_LOCK_TIME_OUT = 55 * 5;
    private PowerManager.WakeLock wakeLock;

    @SuppressLint("InvalidWakeLockTag")
    @Override
    public void onCreate() {
        super.onCreate();
        //初始化通知管理器，8.0以上版本建立通知渠道
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            ControlNotificationManager
                    .getInstance()
                    .init();
        }
        final Notification notification =
                ControlNotificationManager.getInstance()
                        .createPermanentNotification("当前状态：初始化",
                                "渝电监理GPS人员监理管控系统",
                                "com.example.tepthydjl.MainActivity");
        ControlPreference.addCustomAppProfile(SpKey.KEY_ONLINE_STATUS, LineStatus.INIT_STATUS);
        startForeground(CONTROL_SERVICE_ID, notification);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
            Intent innerIntent = new Intent(this, GrayInnerService.class);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                startForegroundService(innerIntent);
            } else {
                // Pre-O behavior.
                startService(innerIntent);
            }
        }
        //注册EventBus
        EventBus.getDefault().register(this);
        synchronized (lock) {
            if (mLocationClient == null) {
                // 定位初始化
                mLocationClient = new LocationClient(Control.getApplicationContext());
                mLocationClient.setLocOption(getDefaultLocationClientOption());
                mLocationClient.registerLocationListener(mControlLocationListener);
                mLocationClient.enableLocInForeground(CONTROL_SERVICE_ID, notification);
                mLocationClient.start();
            }
        }
        final PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
        wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakelockTag");
        wakeLock.setReferenceCounted(false);
        if (wakeLock != null) {
            wakeLock.acquire(WAKE_LOCK_TIME_OUT);
        }
        startTask();
    }

    private ThreadUtils.Task mTask = new ThreadUtils.SimpleTask() {
        @Nullable
        @Override
        public Object doInBackground() {
            if (wakeLock != null) {
                wakeLock.acquire(WAKE_LOCK_TIME_OUT);
            }
            if (mLocationClient != null) {
                mLocationClient.requestLocation();
            }
            return null;
        }

        @Override
        public void onSuccess(@Nullable Object result) {

        }
    };

    private void startTask() {
        ThreadUtils.executeBySingleAtFixRate(mTask, WAKE_LOCK_TIME_OUT, TimeUnit.SECONDS);
    }

    @SuppressLint("WrongConstant")
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, START_STICKY, startId);
    }

    @Subscribe()
    public void requestLocation(RequestLocationEvent event) {
        if (mLocationClient != null) {
            mLocationClient.requestLocation();
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    /**
     * 默认百度地图设置
     *
     * @return LocationClientOption  默认设置
     */
    public LocationClientOption getDefaultLocationClientOption() {
        final LocationClientOption mOption = new LocationClientOption();
        //可选，默认高精度，设置定位模式，高精度，低功耗，仅设备
        mOption.setLocationMode(LocationClientOption.LocationMode.Hight_Accuracy);
        //可选，默认gcj02，设置返回的定位结果坐标系，如果配合百度地图使用，建议设置为bd09ll;
        mOption.setCoorType("gcj02");
        //可选，默认0，即仅定位一次，设置发起连续定位请求的间隔需要大于等于1000ms才是有效的
        mOption.setScanSpan(30 * 1000);
        //可选，设置是否需要地址信息，默认不需要
        mOption.setIsNeedAddress(false);
        //可选，设置是否需要地址描述
        mOption.setIsNeedLocationDescribe(false);
        //可选，设置是否需要设备方向结果
        mOption.setNeedDeviceDirect(false);
        //可选，默认false，设置是否当gps有效时按照1S1次频率输出GPS结果
        mOption.setLocationNotify(false);
        //可选，默认true，定位SDK内部是一个SERVICE，并放到了独立进程，设置是否在stop的时候杀死这个进程，默认不杀死
        mOption.setIgnoreKillProcess(true);
        //可选，默认false，设置是否需要位置语义化结果，可以在BDLocation.getLocationDescribe里得到，结果类似于“在北京天安门附近”
        mOption.setIsNeedLocationDescribe(false);
        //可选，默认false，设置是否需要POI结果，可以在BDLocation.getPoiList里得到
        mOption.setIsNeedLocationPoiList(false);
        //可选，默认false，设置是否收集CRASH信息，默认收集
        mOption.SetIgnoreCacheException(false);
        //可选，默认false，设置是否开启Gps定位
        mOption.setOpenGps(true);
        //可选，默认false，设置定位时是否需要海拔信息，默认不需要，除基础定位版本都可用
        mOption.setIsNeedAltitude(false);
        return mOption;
    }

    @Override
    public void onDestroy() {
        EventBus.getDefault().unregister(this);
        if (mLocationClient != null && mLocationClient.isStarted()) {
            mLocationClient.disableLocInForeground(true);
            mLocationClient.unRegisterLocationListener(mControlLocationListener);
            mLocationClient.stop();
        }
        if (wakeLock != null) {
            wakeLock.release();
        }
        super.onDestroy();
    }

    /**
     * 给 API >= 18 的平台上用的灰色保活手段
     */
    public static class GrayInnerService extends Service {
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            startForeground(CONTROL_SERVICE_ID, new Notification());
            stopForeground(true);
            stopSelf();
            return super.onStartCommand(intent, flags, startId);
        }

        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    }

    @Subscribe(threadMode = ThreadMode.ASYNC)
    public void updateLocation(LocationEvent event) {
        final BDLocation location = event.getBDLocation();
        if (location == null) {
            return;
        }
        SoapClient.builder()
                .methodName(ApiDictionary.API_GET_SERVICE_DATE)
                .nameSpace(ApiDictionary.SOAP_NAME_SPACE)
                .success(new ISoapSuccess() {
                    @Override
                    public void onSuccess(SoapObject object) {
                        final int code = Integer.parseInt(object.getProperty("Code").toString());
                        if (code == CommonParams.SUCCESS_CODE_ZERO) {
                            String serviceDate = object
                                    .getPropertyAsString("Value");
                            String desc = location.getLocType() == BDLocation.TypeGpsLocation ? "gps"
                                    : "network";
                            if (LocationUtil.isAllowMockLocation()) {
                                desc = "error_" + desc;
                            }
                            gpsList.add(new Gps()
                                    .setTime(serviceDate)
                                    .setLatitude(location.getLatitude())
                                    .setLongitude(location.getLongitude())
                                    .setAccuracy(location.getRadius() + "")
                                    .setBearing(location.getDirection() + "")
                                    .setSpeed(location.getSpeed() + "")
                                    .setGpsTime(location.getTime())
                                    .setImei(ConfigManager.getInstance().getPhoneId())
                                    .setUid(ConfigManager.getInstance().getUid())
                                    .setDesc(desc)
                                    .toJSONObject());
                            if (gpsList.size() > MAX_GPS_LIST_SIZE) {
                                gpsList.remove(0);
                            }
                            if (gpsList.isEmpty()) {
                                return;
                            }
                            final JSONObject jsonObject = new JSONObject();
                            jsonObject.put("obj", gpsList);
                            final WeakHashMap<String, Object> params = new WeakHashMap<>();
                            final String jsonString = JSON.toJSONString(jsonObject,
                                    SerializerFeature.WriteMapNullValue,
                                    SerializerFeature.WriteNullListAsEmpty,
                                    SerializerFeature.WriteNullStringAsEmpty,
                                    SerializerFeature.WriteNullBooleanAsFalse,
                                    SerializerFeature.WriteNullNumberAsZero,
                                    SerializerFeature.WriteNonStringValueAsString);
                            params.put("jsonString", jsonString);
                            SoapClient.builder()
                                    .params(params)
                                    .methodName(ApiDictionary.API_ADD_GPS)
                                    .nameSpace(ApiDictionary.SOAP_NAME_SPACE)
                                    .success(new ISoapSuccess() {
                                        @Override

                                        public void onSuccess(SoapObject object) {
                                            final int code = Integer.parseInt(object.getProperty("Code").toString());
                                            if (code == CommonParams.SUCCESS_CODE_NORMAL) {
                                                final String text = object.getPropertyAsString("Text");
                                                gpsList.clear();
                                                //保存最后上传GPS成功的时间
                                                ControlPreference.addCustomAppProfile(SpKey.KEY_LAST_UPDATE_TIME, text);
                                                final SoapObject value = (SoapObject) object
                                                        .getProperty("Value");
                                                handlerNotification(value);
                                            } else {
                                                if (object.hasProperty("Text")) {
                                                    BuglyLog.e(ApiDictionary.API_ADD_GPS, "错误码：" + code + "====TEXT：====" + object.getPropertyAsString("Text"));
                                                } else {
                                                    BuglyLog.e(ApiDictionary.API_ADD_GPS, "错误码：" + code);
                                                }
                                            }
                                        }
                                    })
                                    .builder()
                                    .post();
                            final String lastTime = ControlPreference.getPreferenceString(SpKey.KEY_LAST_UPDATE_TIME);
                            final int oldStatus = ControlPreference.getPreferenceInteger(SpKey.KEY_ONLINE_STATUS);
                            String statusStr;
                            int status;
                            if ("".equals(lastTime)) {
                                status = LineStatus.INIT_STATUS;
                                statusStr = "初始化";
                            } else if (TimeUtils.getTimeSpan(serviceDate, lastTime, TimeConstants.SEC) > OVER_TIME_SECOND) {
                                status = LineStatus.OUTLINE_STATUS;
                                statusStr = "离线";
                            } else {
                                status = LineStatus.ONLINE_STATUS;
                                statusStr = "在线";
                            }
                            if (oldStatus != status) {
                                final Notification notification =
                                        ControlNotificationManager.getInstance()
                                                .createPermanentNotification("当前状态：" + statusStr,
                                                        Control.getApplicationContext().getString(R.string.channel_description),
                                                        "com.example.tepthydjl.MainActivity");
                                ControlNotificationManager.getInstance().showNotification(CONTROL_SERVICE_ID, notification);
                                ControlPreference.addCustomAppProfile(SpKey.KEY_ONLINE_STATUS, status);
                            }
                            EventBus.getDefault().post(CalendarEvent.getInstance()
                                    .setShowCalendar(serviceDate)
                                    .setLineStatus(status));
                        }
                    }
                })
                .builder()
                .post();
    }

    private void handlerNotification(SoapObject value) {
        if (value == null) {
            return;
        }
        for (int i = 0; i < value.getPropertyCount(); i++) {
            SoapObject soapObject = (SoapObject) value
                    .getProperty(i);
            final NotificationBean bean = new NotificationBean()
                    .setReceiveId(Integer.parseInt(soapObject.getPropertySafelyAsString("RecevUid")))
                    .setContext(soapObject.getPropertySafelyAsString("MContext"))
                    .setCurrentDate(soapObject.getPropertySafelyAsString("CurrentDate"))
                    .setSendId(Integer.parseInt(soapObject.getPropertySafelyAsString("SendUid")))
                    .setType(Integer.parseInt(soapObject.getPropertySafelyAsString("MType")))
                    .setTargetId(Integer.parseInt(soapObject.getPropertySafelyAsString("TargetId")));
            final Notification notification = ControlNotificationManager.getInstance()
                    .createNormalNotification("com.example.tepthydjl.MainActivity", bean);
            ControlNotificationManager.getInstance().showNotification(bean.getTargetId(), notification);
        }
    }
}
